﻿using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace Micro.Common.Helper
{
    public sealed partial class ImgHelper
    {
        /// <summary>
        /// Image 转成 base64
        /// </summary>
        /// <param name="imagePath"></param>
        /// <returns></returns>
        public static string ImageToBase64(string imagePath)
        {
            using (Image<Rgba32> image = Image.Load<Rgba32>(imagePath))
            {
                using (var ms = new MemoryStream())
                {
                    image.Save(ms, new JpegEncoder() { Quality = 100 }); // 保存到内存流
                    var imageBytes = ms.ToArray();
                    return Convert.ToBase64String(imageBytes);
                }
            }
        }

        /// <summary>
        /// Base64图片去掉前缀
        /// </summary>
        /// <param name="base64String"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static string Base64RemovePrefix(string base64String)
        {
            if (string.IsNullOrWhiteSpace(base64String)) return string.Empty;

            // 寻找逗号的索引，指示 Base64 编码的真正起始位置
            int commaIndex = base64String.IndexOf(',');
            if (commaIndex != -1)
                // 返回去掉前缀的 Base64 字符串
                return base64String.Substring(commaIndex + 1);
            return base64String;
        }

        /// <summary>
        /// Base64图片去掉前缀
        /// </summary>
        /// <param name="base64String"></param>
        /// <returns></returns>
        public static string RemoveBase64Prefix(string base64String)
        {
            const string prefix = "data:image/";
            int prefixLength = base64String.IndexOf(',', StringComparison.Ordinal);
            if (prefixLength > 0)
            {
                return base64String.Substring(prefixLength + 1);
            }
            return base64String;
        }

        /// <summary>
        /// 压缩base64图片
        /// </summary>
        /// <param name="base64Image"></param>
        /// <param name="targetSizeKB"></param>
        /// <returns></returns>
        public static string CompressBase64Image(string base64Image, int targetSizeKB = 200, int maxWidth = 400)
        {
            if (string.IsNullOrEmpty(base64Image)) return string.Empty;
            // Decode base64 string to byte array
            byte[] imageBytes = Convert.FromBase64String(base64Image.Split(',').LastOrDefault());

            // Load the image
            using (var image = Image.Load<Rgba32>(imageBytes))
            {
                // Otherwise, iteratively decrease quality until target size is met
                int maxStep = 100;

                int perStep = 2;//每次压缩间隔大小

                // Define compression parameters
                var encoder = new JpegEncoder() { Quality = maxStep };// Start with max quality and reduce if necessary

                // Initial output stream
                using (var outputStream = new MemoryStream())
                {
                    if (image.Width > maxWidth) image.Mutate(o => o.Resize(maxWidth, default, KnownResamplers.Lanczos8));

                    // Save the image to the stream with max quality
                    image.Save(outputStream, encoder);

                    // If the size is less than target, return the image as base64
                    if (outputStream.Length <= targetSizeKB * 1024) return Convert.ToBase64String(outputStream.ToArray());

                    while (maxStep > 0)
                    {
                        // Reset the stream
                        outputStream.SetLength(0);

                        // Reduce quality for the next iteration
                        maxStep -= perStep; // Adjust step size as needed

                        encoder = new JpegEncoder() { Quality = maxStep };

                        // Save the image with the new quality setting
                        image.Save(outputStream, encoder);

                        // Check if the resulting size is under the target size
                        if (outputStream.Length <= targetSizeKB * 1024) return Convert.ToBase64String(outputStream.ToArray());
                    }

                    // If all iterations fail, return the smallest quality image
                    return Convert.ToBase64String(outputStream.ToArray());
                }
            }
        }

        /// <summary>
        /// 图片转文件流
        /// </summary>
        /// <param name="imagePath"></param>
        /// <returns></returns>
        public static MemoryStream ImageToStream(string imagePath)
        {
            // 使用 MemoryStream 创建一个内存流来保存图片数据
            using (var ms = new MemoryStream())
            {
                // 从文件加载图片
                using (Image<Rgba32> image = Image.Load<Rgba32>(imagePath))
                {
                    // 将图片保存到内存流中
                    image.Save(ms, new JpegEncoder() { Quality = 100 });
                }

                // 将内存流的指针重置到流的开头
                ms.Position = 0;
                return new MemoryStream(ms.ToArray());
            }
        }

        /// <summary>
        /// 压缩图片文件流
        /// </summary>
        /// <param name="inputMemoryStream"></param>
        /// <param name="quality"></param>
        /// <returns></returns>
        public static MemoryStream CompressImageMemoryStream(MemoryStream inputMemoryStream, int targetSizeKB)
        {
            // 注意：确保inputMemoryStream的Position在开始时是0，以便可以从头开始读取
            inputMemoryStream.Position = 0;

            // 创建一个新的内存流来保存压缩后的图像
            using (var outputMemoryStream = new MemoryStream())
            {
                // 加载图像
                using (var image = SixLabors.ImageSharp.Image.Load(inputMemoryStream))
                {
                    int targetSizeBytes = targetSizeKB * 1024;

                    int fileSize = 0;
                    int.TryParse(inputMemoryStream.Length.ToString(), out fileSize);

                    double scaleFactor = Math.Sqrt((double)fileSize / targetSizeBytes);

                    int newWidth = (int)(image.Width / scaleFactor);
                    int newHeight = (int)(image.Height / scaleFactor);

                    image.Mutate(x => x.Resize(newWidth, newHeight));

                    // 配置JPEG编码器设置

                    // 保存图像到新的内存流，使用指定的编码器设置
                    image.Save(outputMemoryStream, new JpegEncoder());

                    // 重置输出流的位置，以便可以从其开始处读取数据
                    outputMemoryStream.Position = 0;

                    // 因为outputMemoryStream是在using块中创建的，我们不能直接返回它（因为它会在using块结束时被释放）
                    // 所以我们需要复制outputMemoryStream的内容到一个新的MemoryStream中并返回它
                    return new MemoryStream(outputMemoryStream.ToArray());
                }
            }
        }

        /// <summary>
        /// 压缩图片文件流
        /// </summary>
        /// <param name="inputMemoryStream"></param>
        /// <param name="targetSizeKB"></param>
        /// <param name="maxWidth"></param>
        /// <returns></returns>
        public static MemoryStream CompressImageMemoryStream(MemoryStream inputMemoryStream, int targetSizeKB = 200, int maxWidth = 400)
        {
            // 注意：确保inputMemoryStream的Position在开始时是0，以便可以从头开始读取
            inputMemoryStream.Position = 0;

            // 创建一个新的内存流来保存压缩后的图像
            using (var outputStream = new MemoryStream())
            {
                // 加载图像
                using (var image = SixLabors.ImageSharp.Image.Load(inputMemoryStream))
                {
                    int maxStep = 100; //最大图片质量
                    int perStep = 2; //每次压缩间隔大小
                    var encoder = new JpegEncoder() { Quality = maxStep };// 图片质量设置

                    //如果图片宽度大于指定宽度，则先调整到指定宽度
                    if (image.Width > maxWidth) image.Mutate(o => o.Resize(maxWidth, default, KnownResamplers.Lanczos8));
                    image.Save(outputStream, encoder);

                    //如果图片尺寸小于指定大小，则直接返回
                    if (outputStream.Length <= targetSizeKB * 1024) return new MemoryStream(outputStream.ToArray());

                    while (maxStep > 0)
                    {
                        outputStream.SetLength(0);//重置流
                        maxStep -= perStep; // 降低图片质量
                        encoder = new JpegEncoder() { Quality = maxStep };
                        image.Save(outputStream, encoder);//保存图片到流

                        // 如果图片大小达到了指定大小，则返回
                        if (outputStream.Length <= targetSizeKB * 1024) return new MemoryStream(outputStream.ToArray());
                    }
                    return new MemoryStream(outputStream.ToArray());
                }
            }
        }

        /// <summary>
        /// 图片转字节
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static byte[] ImageToBytes(string imagePath)
        {
            using (var ms = new MemoryStream())
            {
                // 从文件加载图片
                using (Image<Rgba32> image = Image.Load<Rgba32>(imagePath))
                {
                    // 将图片保存到内存流中
                    image.Save(ms, new JpegEncoder() { Quality = 100 });
                }
                // 返回字节数组
                return ms.ToArray();
            }
        }
    }
}